{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "%pylab is deprecated, use %matplotlib inline and import the required libraries.\n",
      "Populating the interactive namespace from numpy and matplotlib\n"
     ]
    }
   ],
   "source": [
    "%pylab inline"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/Users/zhaoming/00.works/python-deltasigma/examples/../deltasigma/_config.py:54: UserWarning: Cannot find the path for 'cblas.h'. You may set it using the environment variable BLAS_H.\n",
      "NOTE: You need to pass the path to the directories were the header files are, not the path to the files.\n",
      "  warn(\"Cannot find the path for 'cblas.h'. You may set it using the environment variable \"\n"
     ]
    }
   ],
   "source": [
    "import sys\n",
    "sys.path.append('..')\n",
    "from __future__ import division\n",
    "from deltasigma import *"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "NTF synthesis - demo #1\n",
    "=======================\n",
    "\n",
    "Demonstration of the **`synthesizeNTF`** function, as done in the **MATLAB Delta Sigma Toolbox**, employing its Python port **`deltasigma`**.\n",
    "\n",
    "\n",
    "\n",
    " * The **Noise Transfer Function** (NTF) is synthesized for a **5th-order**, **low-pass** modulator.\n",
    "\n",
    "     * The first section deals with an **NTF without optimized zeros** (`opt=0`), \n",
    "     * while the second section with an **NTF *with optimized* zeros** (`opt=1`). \n",
    "     * Finally the two transfer functions are compared.\n",
    "\n",
    " * Then we move on to the synthesis of an **8th-order band-pass modulator** with optimized zeros."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "5th-order modulator\n",
    "-------------------\n",
    "\n",
    "General parameters:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "order = 5\n",
    "OSR = 160//3"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 5th-order modulator: NTF without zeros optimization\n",
    "\n",
    "The synthesis of an NTF can be performed with the `synthesizeNTF(order, OSR, opt)`.\n",
    "\n",
    "We intentionally disable the zeros optimization, setting `opt=0`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# Synthesize!\n",
    "H0 = synthesizeNTF(order, OSR, opt=0)\n",
    "# 1. Plot the singularities.\n",
    "subplot(121)\n",
    "plotPZ(H0, markersize=5)\n",
    "title('NTF Poles and Zeros')\n",
    "f = np.concatenate((np.linspace(0, 0.75/OSR, 100), np.linspace(0.75/OSR, 0.5, 100)))\n",
    "z = np.exp(2j*np.pi*f)\n",
    "magH0 = dbv(evalTF(H0, z))\n",
    "# 2. Plot the magnitude responses.\n",
    "subplot(222)\n",
    "plot(f, magH0)\n",
    "figureMagic([0, 0.5], 0.05, None, [-100, 10], 10, None, (16, 8))\n",
    "xlabel('Normalized frequency ($1\\\\rightarrow f_s)$')\n",
    "ylabel('dB')\n",
    "title('NTF Magnitude Response')\n",
    "# 3. Plot the magnitude responses in the signal band.\n",
    "subplot(224)\n",
    "fstart = 0.01\n",
    "f = np.linspace(fstart, 1.2, 200)/(2*OSR)\n",
    "z = np.exp(2j*np.pi*f)\n",
    "magH0 = dbv(evalTF(H0, z))\n",
    "semilogx(f*2*OSR, magH0)\n",
    "axis([fstart, 1.2, -100,- 30])\n",
    "grid(True)\n",
    "sigma_H0 = dbv(rmsGain(H0, 0, 0.5/OSR))\n",
    "#semilogx([fstart, 1], sigma_H0*np.array([1, 1]))\n",
    "semilogx([fstart, 1], sigma_H0*np.array([1, 1]),'-o')\n",
    "text(0.15, sigma_H0 + 5, 'rms gain = %5.0fdB' % sigma_H0)\n",
    "xlabel('Normalized frequency ($1\\\\rightarrow f_B$)')\n",
    "ylabel('dB')\n",
    "tight_layout()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 5th-order modulator: NTF *with* zeros optimization\n",
    "\n",
    "This time we enable the zeros optimization, setting `opt=1` when calling synthesizeNTF(), then replot the NTF as above."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# Synthesize again!\n",
    "H0 = None\n",
    "H1 = synthesizeNTF(order, OSR, opt=1)\n",
    "# 1. Plot the singularities.\n",
    "subplot(121)\n",
    "plotPZ(H1, markersize=5)\n",
    "title('NTF Poles and Zeros')\n",
    "f = np.concatenate((np.linspace(0, 0.75/OSR, 100), np.linspace(0.75/OSR, 0.5, 100)))\n",
    "z = np.exp(2j*np.pi*f)\n",
    "magH1 = dbv(evalTF(H1, z))\n",
    "# 2. Plot the magnitude responses.\n",
    "subplot(222)\n",
    "plot(f, magH1)\n",
    "figureMagic([0, 0.5], 0.05, None, [-100, 10], 10, None, (16, 8))\n",
    "xlabel('Normalized frequency ($1\\\\rightarrow f_s)$')\n",
    "ylabel('dB')\n",
    "title('NTF Magnitude Response')\n",
    "# 3. Plot the magnitude responses in the signal band.\n",
    "subplot(224)\n",
    "fstart = 0.01\n",
    "f = np.linspace(fstart, 1.2, 200)/(2*OSR)\n",
    "z = np.exp(2j*np.pi*f)\n",
    "magH1 = dbv(evalTF(H1, z))\n",
    "semilogx(f*2*OSR, magH1)\n",
    "axis([fstart, 1.2, -100,- 30])\n",
    "grid(True)\n",
    "sigma_H1 = dbv(rmsGain(H1, 0, 0.5/OSR))\n",
    "#semilogx([fstart, 1], sigma_H1*np.array([1, 1]))\n",
    "semilogx([fstart, 1], sigma_H1*np.array([1, 1]),'-o')\n",
    "text(0.15, sigma_H1 + 5, 'RMS gain = %5.0fdB' % sigma_H1)\n",
    "xlabel('Normalized frequency ($1\\\\rightarrow f_B$)')\n",
    "ylabel('dB')\n",
    "tight_layout()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "5th-order modulator: comparison\n",
    "-------------------------------\n",
    "\n",
    "Overlayed plots follow to ease comparison of the two synthetization approaches."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# Synthesize!\n",
    "H0 = synthesizeNTF(order, OSR, opt=0)\n",
    "H1 = synthesizeNTF(order, OSR, opt=1)\n",
    "# 1. Plot the singularities.\n",
    "subplot(121)\n",
    "# we plot the singularities of the optimized NTF in light \n",
    "# green with slightly bigger markers so that we can better\n",
    "# distinguish the two NTF's when overlayed.\n",
    "plotPZ(H1, markersize=7, color='#90EE90')\n",
    "# hold(True)\n",
    "plotPZ(H0, markersize=5)\n",
    "title('NTF Poles and Zeros')\n",
    "f = np.concatenate((np.linspace(0, 0.75/OSR, 100), np.linspace(0.75/OSR, 0.5, 100)))\n",
    "z = np.exp(2j*np.pi*f)\n",
    "magH0 = dbv(evalTF(H0, z))\n",
    "magH1 = dbv(evalTF(H1, z))\n",
    "# 2. Plot the magnitude responses.\n",
    "subplot(222)\n",
    "plot(f, magH0, label='All zeros in z=1')\n",
    "# hold(True)\n",
    "plot(f, magH1, label='Optimized zeros')\n",
    "figureMagic([0, 0.5], 0.05, None, [-100, 10], 10, None, (16, 8))\n",
    "xlabel('Normalized frequency ($1\\\\rightarrow f_s)$')\n",
    "ylabel('dB')\n",
    "legend(loc=4)\n",
    "title('NTF Magnitude Response')\n",
    "# 3. Plot the magnitude responses in the signal band.\n",
    "subplot(224)\n",
    "fstart = 0.01\n",
    "f = np.linspace(fstart, 1.2, 200)/(2*OSR)\n",
    "z = np.exp(2j*np.pi*f)\n",
    "magH0 = dbv(evalTF(H0, z))\n",
    "magH1 = dbv(evalTF(H1, z))\n",
    "semilogx(f*2*OSR, magH0, label='All zeros in z=1')\n",
    "# hold(True)\n",
    "semilogx(f*2*OSR, magH1, label='Optimized zeros')\n",
    "axis([fstart, 1.2, -100,- 30])\n",
    "grid(True)\n",
    "sigma_H0 = dbv(rmsGain(H0, 0, 0.5/OSR))\n",
    "sigma_H1 = dbv(rmsGain(H1, 0, 0.5/OSR))\n",
    "#semilogx([fstart, 1], sigma_H0*np.array([1, 1]))\n",
    "plot([fstart, 1], sigma_H0*np.array([1, 1]), 'o-')\n",
    "text(0.15, sigma_H0 + 5, 'RMS gain = %5.0fdB' % sigma_H0)\n",
    "#semilogx([fstart, 1], sigma_H1*np.array([1, 1]))\n",
    "plot([fstart, 1], sigma_H1*np.array([1, 1]), 'o-')\n",
    "text(0.15, sigma_H1 + 5, 'RMS gain = %5.0fdB' % sigma_H1)\n",
    "xlabel('Normalized frequency ($1\\\\rightarrow f_B$)')\n",
    "ylabel('dB')\n",
    "legend(loc=4)\n",
    "tight_layout()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "8th-order bandpass Modulator\n",
    "----------------------------\n",
    "In the following, we synthesize an 8th-order modulator with optimized zeros."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/var/folders/5k/blch4xw910dcskrtzns2bjz00000gn/T/ipykernel_78975/2549958519.py:34: UserWarning: Attempt to set non-positive xlim on a log-scaled axis will be ignored.\n",
      "  axis([- 0.6, 0.6, -100, -60])\n",
      "/var/folders/5k/blch4xw910dcskrtzns2bjz00000gn/T/ipykernel_78975/2549958519.py:43: UserWarning: Tight layout not applied. tight_layout cannot make axes width small enough to accommodate all axes decorations\n",
      "  tight_layout()\n"
     ]
    }
   ],
   "source": [
    "order = 8\n",
    "OSR = 64\n",
    "opt = 2\n",
    "f0 = 0.125\n",
    "H = synthesizeNTF(order, OSR, opt, 1.5, f0)\n",
    "subplot(121)\n",
    "plotPZ(H)\n",
    "title('Bandpass NTF Poles and Zeros')\n",
    "f = np.concatenate((np.linspace(0, f0 - 1./(2.*OSR), 50), \n",
    "                    np.linspace(f0 - 1./ (2 * OSR), f0 + 1./(2.*OSR), 100), \n",
    "                    np.linspace(f0 + 1./(2.*OSR), 0.5, 50)))\n",
    "z = np.exp(2j * pi * f)\n",
    "magH = dbv(evalTF(H, z))\n",
    "subplot(222)\n",
    "plot(f, magH)\n",
    "# hold(True)\n",
    "G = (np.zeros((order//2,)), H[1], 1)\n",
    "k = 1./np.abs(evalTF(G, np.exp(2j*np.pi*f0)))\n",
    "G = (G[0], G[1], k)\n",
    "magG = dbv(evalTF(G, z))\n",
    "plot(f, magG, 'r')\n",
    "figureMagic([0, 0.5], 0.05, None, [-100, 10], 10, None, (16, 8))\n",
    "#axis([0, 0.5, -100, 10])\n",
    "grid(True)\n",
    "xlabel('Normalized frequency ($1 \\\\rightarrow fs$)')\n",
    "ylabel('dB')\n",
    "title('Bandpass NTF/STF Magnitude Response')\n",
    "f = np.linspace(f0 - 0.3/OSR, f0 + 0.3/OSR)\n",
    "z = np.exp(2j*np.pi*f)\n",
    "magH = dbv(evalTF(H, z))\n",
    "subplot(224)\n",
    "fstart = -.5\n",
    "plot(2*OSR*(f - f0), magH)\n",
    "axis([- 0.6, 0.6, -100, -60])\n",
    "grid(True)\n",
    "sigma_H = dbv(rmsGain(H, f0 - 0.25/OSR, f0 + 0.25/OSR))\n",
    "# hold(True)\n",
    "#plot([-0.5, 0.5], sigma_H*np.array([1, 1]))\n",
    "plot([-0.5, 0.5], sigma_H*np.array([1, 1]), 'o-')\n",
    "text(-.2, sigma_H + 5, 'rms gain = %5.0fdB' % sigma_H)\n",
    "xlabel('Normalized frequency offset')\n",
    "ylabel('dB')\n",
    "tight_layout()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Further information about NTF synthesis\n",
    "---------------------------------------\n",
    "\n",
    "Please refer to `help(synthesizeNTF)` for detailed - and possibly more updated - documentation!\n",
    "\n",
    "###`help(synthesizeNTF)` as of writing:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "Help on function synthesizeNTF in module deltasigma._synthesizeNTF:\n",
    "\n",
    "**synthesizeNTF(order=3, osr=64, opt=0, H_inf=1.5, f0=0.0)**\n",
    "\n",
    "Synthesize a noise transfer function for a delta-sigma modulator.\n",
    "\n",
    "**Parameters:**\n",
    "\n",
    "order : *int, optional*\n",
    "    the order of the modulator, defaults to 3\n",
    "\n",
    "osr : *float, optional*\n",
    "    the oversamping ratio, defaults to 64\n",
    "\n",
    "opt : *int or list of floats, optional*\n",
    "    flag for optimized zeros, defaults to 0\n",
    "\n",
    "* 0 -> not optimized,\n",
    "* 1 -> optimized,\n",
    "* 2 -> optimized with at least one zero at band-center,\n",
    "* 3 -> optimized zeros (with optimizer)\n",
    "* 4 -> same as 3, but with at least one zero at band-center\n",
    "* [z] -> zero locations in complex form\n",
    "\n",
    "H_inf : *real, optional*\n",
    "    max allowed peak value of the NTF. Defaults to 1.5\n",
    "\n",
    "f0 : *real, optional*\n",
    "    center frequency for BP modulators, or 0 for LP modulators.\n",
    "    Defaults to 0.\n",
    "\n",
    "    1 corresponds to the sampling frequency, so that 0.5 is the\n",
    "    maximum value. A value of 0 specifies an LP modulator.\n",
    "\n",
    "**Returns:**\n",
    "\n",
    "ntf : *tuple*\n",
    "    noise transfer function in zpk form.\n",
    "\n",
    "**Raises:**\n",
    "\n",
    "ValueError\n",
    "\n",
    "* 'Error. f0 must be less than 0.5' if f0 is out of range\n",
    "\n",
    "* 'Order must be even for a bandpass modulator.' if the order is\n",
    "  incompatible with the modulator type.\n",
    "\n",
    "* 'The opt vector must be of length xxx' if opt is used to explicitly\n",
    "  pass the NTF zeros and these are in the wrong number.\n",
    "\n",
    "**Warns:**\n",
    "\n",
    "* 'Creating a lowpass ntf.' if the center frequency is different\n",
    "  from zero, but so low that a low pass modulator must be designed.\n",
    "\n",
    "* 'Unable to achieve specified H_inf ...' if the desired H_inf\n",
    "  cannot be achieved.\n",
    "\n",
    "* 'Iteration limit exceeded' if the routine converges too slowly.\n",
    "\n",
    "**Notes:**\n",
    "\n",
    "This is actually a wrapper function which calls the appropriate version\n",
    "of synthesizeNTF, based on the module control flag `optimize_NTF` which\n",
    "determines whether to use optimization tools.\n",
    "\n",
    "Parameter ``H_inf`` is used to enforce the Lee stability criterion.\n",
    "\n",
    "**See also:**\n",
    "\n",
    "* `clans()` : Closed-Loop Analysis of Noise-Shaper. \n",
    "\n",
    "An alternative method for selecting NTFs based on the 1-norm of the \n",
    "      impulse response of the NTF\n",
    "    \n",
    "* `synthesizeChebyshevNTF()` : Select a type-2 highpass Chebyshev NTF.\n",
    "\n",
    "This function does a better job than synthesizeNTF if osr\n",
    "   or H_inf is low."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### System version information"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "ename": "ModuleNotFoundError",
     "evalue": "No module named 'version_information'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mModuleNotFoundError\u001b[0m                       Traceback (most recent call last)",
      "Cell \u001b[0;32mIn [8], line 2\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[39m#%install_ext http://raw.github.com/jrjohansson/version_information/master/version_information.py\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m get_ipython()\u001b[39m.\u001b[39;49mrun_line_magic(\u001b[39m'\u001b[39;49m\u001b[39mload_ext\u001b[39;49m\u001b[39m'\u001b[39;49m, \u001b[39m'\u001b[39;49m\u001b[39mversion_information\u001b[39;49m\u001b[39m'\u001b[39;49m)\n\u001b[1;32m      3\u001b[0m get_ipython()\u001b[39m.\u001b[39mrun_line_magic(\u001b[39m'\u001b[39m\u001b[39mreload_ext\u001b[39m\u001b[39m'\u001b[39m, \u001b[39m'\u001b[39m\u001b[39mversion_information\u001b[39m\u001b[39m'\u001b[39m)\n\u001b[1;32m      5\u001b[0m get_ipython()\u001b[39m.\u001b[39mrun_line_magic(\u001b[39m'\u001b[39m\u001b[39mversion_information\u001b[39m\u001b[39m'\u001b[39m, \u001b[39m'\u001b[39m\u001b[39mnumpy, scipy, matplotlib, deltasigma\u001b[39m\u001b[39m'\u001b[39m)\n",
      "File \u001b[0;32m~/Library/Python/3.11/lib/python/site-packages/IPython/core/interactiveshell.py:2364\u001b[0m, in \u001b[0;36mInteractiveShell.run_line_magic\u001b[0;34m(self, magic_name, line, _stack_depth)\u001b[0m\n\u001b[1;32m   2362\u001b[0m     kwargs[\u001b[39m'\u001b[39m\u001b[39mlocal_ns\u001b[39m\u001b[39m'\u001b[39m] \u001b[39m=\u001b[39m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39mget_local_scope(stack_depth)\n\u001b[1;32m   2363\u001b[0m \u001b[39mwith\u001b[39;00m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39mbuiltin_trap:\n\u001b[0;32m-> 2364\u001b[0m     result \u001b[39m=\u001b[39m fn(\u001b[39m*\u001b[39;49margs, \u001b[39m*\u001b[39;49m\u001b[39m*\u001b[39;49mkwargs)\n\u001b[1;32m   2365\u001b[0m \u001b[39mreturn\u001b[39;00m result\n",
      "File \u001b[0;32m~/Library/Python/3.11/lib/python/site-packages/IPython/core/magics/extension.py:33\u001b[0m, in \u001b[0;36mExtensionMagics.load_ext\u001b[0;34m(self, module_str)\u001b[0m\n\u001b[1;32m     31\u001b[0m \u001b[39mif\u001b[39;00m \u001b[39mnot\u001b[39;00m module_str:\n\u001b[1;32m     32\u001b[0m     \u001b[39mraise\u001b[39;00m UsageError(\u001b[39m'\u001b[39m\u001b[39mMissing module name.\u001b[39m\u001b[39m'\u001b[39m)\n\u001b[0;32m---> 33\u001b[0m res \u001b[39m=\u001b[39m \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49mshell\u001b[39m.\u001b[39;49mextension_manager\u001b[39m.\u001b[39;49mload_extension(module_str)\n\u001b[1;32m     35\u001b[0m \u001b[39mif\u001b[39;00m res \u001b[39m==\u001b[39m \u001b[39m'\u001b[39m\u001b[39malready loaded\u001b[39m\u001b[39m'\u001b[39m:\n\u001b[1;32m     36\u001b[0m     \u001b[39mprint\u001b[39m(\u001b[39m\"\u001b[39m\u001b[39mThe \u001b[39m\u001b[39m%s\u001b[39;00m\u001b[39m extension is already loaded. To reload it, use:\u001b[39m\u001b[39m\"\u001b[39m \u001b[39m%\u001b[39m module_str)\n",
      "File \u001b[0;32m~/Library/Python/3.11/lib/python/site-packages/IPython/core/extensions.py:76\u001b[0m, in \u001b[0;36mExtensionManager.load_extension\u001b[0;34m(self, module_str)\u001b[0m\n\u001b[1;32m     69\u001b[0m \u001b[39m\"\"\"Load an IPython extension by its module name.\u001b[39;00m\n\u001b[1;32m     70\u001b[0m \n\u001b[1;32m     71\u001b[0m \u001b[39mReturns the string \"already loaded\" if the extension is already loaded,\u001b[39;00m\n\u001b[1;32m     72\u001b[0m \u001b[39m\"no load function\" if the module doesn't have a load_ipython_extension\u001b[39;00m\n\u001b[1;32m     73\u001b[0m \u001b[39mfunction, or None if it succeeded.\u001b[39;00m\n\u001b[1;32m     74\u001b[0m \u001b[39m\"\"\"\u001b[39;00m\n\u001b[1;32m     75\u001b[0m \u001b[39mtry\u001b[39;00m:\n\u001b[0;32m---> 76\u001b[0m     \u001b[39mreturn\u001b[39;00m \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49m_load_extension(module_str)\n\u001b[1;32m     77\u001b[0m \u001b[39mexcept\u001b[39;00m \u001b[39mModuleNotFoundError\u001b[39;00m:\n\u001b[1;32m     78\u001b[0m     \u001b[39mif\u001b[39;00m module_str \u001b[39min\u001b[39;00m BUILTINS_EXTS:\n",
      "File \u001b[0;32m~/Library/Python/3.11/lib/python/site-packages/IPython/core/extensions.py:91\u001b[0m, in \u001b[0;36mExtensionManager._load_extension\u001b[0;34m(self, module_str)\u001b[0m\n\u001b[1;32m     89\u001b[0m \u001b[39mwith\u001b[39;00m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39mshell\u001b[39m.\u001b[39mbuiltin_trap:\n\u001b[1;32m     90\u001b[0m     \u001b[39mif\u001b[39;00m module_str \u001b[39mnot\u001b[39;00m \u001b[39min\u001b[39;00m sys\u001b[39m.\u001b[39mmodules:\n\u001b[0;32m---> 91\u001b[0m         mod \u001b[39m=\u001b[39m import_module(module_str)\n\u001b[1;32m     92\u001b[0m     mod \u001b[39m=\u001b[39m sys\u001b[39m.\u001b[39mmodules[module_str]\n\u001b[1;32m     93\u001b[0m     \u001b[39mif\u001b[39;00m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39m_call_load_ipython_extension(mod):\n",
      "File \u001b[0;32m/opt/homebrew/Cellar/python@3.11/3.11.3/Frameworks/Python.framework/Versions/3.11/lib/python3.11/importlib/__init__.py:126\u001b[0m, in \u001b[0;36mimport_module\u001b[0;34m(name, package)\u001b[0m\n\u001b[1;32m    124\u001b[0m             \u001b[39mbreak\u001b[39;00m\n\u001b[1;32m    125\u001b[0m         level \u001b[39m+\u001b[39m\u001b[39m=\u001b[39m \u001b[39m1\u001b[39m\n\u001b[0;32m--> 126\u001b[0m \u001b[39mreturn\u001b[39;00m _bootstrap\u001b[39m.\u001b[39;49m_gcd_import(name[level:], package, level)\n",
      "File \u001b[0;32m<frozen importlib._bootstrap>:1206\u001b[0m, in \u001b[0;36m_gcd_import\u001b[0;34m(name, package, level)\u001b[0m\n",
      "File \u001b[0;32m<frozen importlib._bootstrap>:1178\u001b[0m, in \u001b[0;36m_find_and_load\u001b[0;34m(name, import_)\u001b[0m\n",
      "File \u001b[0;32m<frozen importlib._bootstrap>:1142\u001b[0m, in \u001b[0;36m_find_and_load_unlocked\u001b[0;34m(name, import_)\u001b[0m\n",
      "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'version_information'"
     ]
    }
   ],
   "source": [
    "#%install_ext http://raw.github.com/jrjohansson/version_information/master/version_information.py\n",
    "%load_ext version_information\n",
    "%reload_ext version_information\n",
    "\n",
    "%version_information numpy, scipy, matplotlib, deltasigma"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3.11.3 64-bit",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.3"
  },
  "vscode": {
   "interpreter": {
    "hash": "b0fa6594d8f4cbf19f97940f81e996739fb7646882a419484c72d19e05852a7e"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
